// ========================================================================
// Copyright 2012 leolee<workspaceleo@gmail.com>
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.jcommon.com.util.system;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.*;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;
import org.jcommon.com.util.SortUtils;
import org.jcommon.com.util.collections.CollectionStore;
import org.jcommon.com.util.jmx.JmxManager;
import org.jcommon.com.util.thread.ThreadManager;

/**
 * 
 * @author LeoLee<leo.li@protel.com.hk>
 *
 */
public class SystemManager extends CollectionStore implements ServletContextListener {
	private static Logger logger = Logger.getLogger(SystemManager.class);
	
	private static SystemManager instance;
	private static Collection<Object> store      = new ArrayList<Object>();
	
	public static InputStream init_file_is = SystemManager.class.getResourceAsStream("/system.xml");
	
	private static final int STARTED  = 1;
	private static final int STARTING = 2;
	private static final int END      = 3;
	
	private static int status         = END;
	
	public static SystemManager instance(){
		if(instance == null){
			logger.warn("SystemManager not Initialized");
			instance = new SystemManager();
		}
		return instance;
	}
	
	public SystemManager(){
		super(store);	
	}
	
	public boolean addListener(SystemListener listener){
		if(status == STARTED || status == STARTING){
			listener.startup();
		}
		return super.addOne(listener);
	}
	
	public boolean addListener(int index, SystemListener listener){
		if(status == STARTED || status == STARTING){
			listener.startup();
		}
		((ArrayList<Object>)store).add(index, listener);
		return true;
	}
	
	public boolean removeListener(SystemListener listener){
		return super.removeOne(listener);
	}
	
	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub
		down();
		close();
		logger.info("SystemManager shutdown");
	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		// TODO Auto-generated method stub
		instance = this;
		logger.info("SystemManager initializing");
		SystemConfig config = SystemConfig.instance();
		config.setConfigUrl(init_file_is);
		config.reloadConfig();
			
		String ROOT       = System.getProperty("user.dir");
		String CONFIG_DIRECTORY = ROOT + File.separator + config.getLib_url();
		SystemClassLoader class_loader = new SystemClassLoader();
		if(config.getLib_url()!=null){
			try {
				class_loader.addDirectory(new File(CONFIG_DIRECTORY));
			} catch (MalformedURLException e1) {
				// TODO Auto-generated catch block
				logger.error("", e1);
			}
		}

		Thread loader_thrad = new Thread(){
			public void run(){
				init();
				SystemManager.this.start();
				registerSystemConfig();
			}
		};
		loader_thrad.setName("class loader thread");
		loader_thrad.setContextClassLoader(class_loader);
		loader_thrad.start();
		logger.info("SystemManager running....");
	}

	private void registerSystemConfig(){
		ObjectName adapterName;
		try {
			adapterName = new ObjectName("SystemConfigAdaptor:name=SystemConfig");
			if(JmxManager.instance()!=null)
				JmxManager.instance().registerMBean(SystemConfig.instance(), adapterName);
		} catch (MalformedObjectNameException e) {
			// TODO Auto-generated catch block
			logger.error("", e);
		} catch (InstanceAlreadyExistsException e) {
			// TODO Auto-generated catch block
			logger.error("", e);
		} catch (MBeanRegistrationException e) {
			// TODO Auto-generated catch block
			logger.error("", e);
		} catch (NotCompliantMBeanException e) {
			// TODO Auto-generated catch block
			logger.error("", e);
		} catch (NullPointerException e) {
			// TODO Auto-generated catch block
			logger.error("", e);
		}	
	}
	private void init() {
		// TODO Auto-generated method stub	
		SystemConfig config = SystemConfig.instance();
		addListener(ThreadManager.instance());
		Map<String,String> listener = config.getSystem_object();
		if(listener!=null){
			String keys[] = SortUtils.sortKey(listener.keySet());
			for(String key: keys){
				try {
					Class<?> c = Class.forName(listener.get(key));
					SystemListener sl = (SystemListener) c.newInstance();
					addListener(sl);
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					logger.error("",e);
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					logger.error("",e);
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					logger.error("",e);
				}
			}
		}
	}

	private void start(){
		logger.info("start ...");
		if(store==null)return;
		status = STARTING;
		synchronized(store){
			for(Object o : store.toArray()){
				logger.info(o+" start ...");
				((SystemListener)o).startup();
			}
		}
		status = STARTED;
	}
	
	private void down(){
		logger.info("down ...");
		if(store==null)return;
		synchronized(store){
			for(Object o : store){
				((SystemListener)o).shutdown();
			}
		}
		status = END;
	}
	
	private void close(){
		super.clear();
		status = END;
	}
	
	public void restart(){
		logger.info("restart ...");
		down();
		start();
		registerSystemConfig();
	}
}
